home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Open Source / AutoHotKey / Source / AutoHotkey104705_source.exe / source / window.h < prev    next >
Encoding:
C/C++ Source or Header  |  2007-01-10  |  16.5 KB  |  330 lines

  1. /*
  2. AutoHotkey
  3.  
  4. Copyright 2003-2007 Chris Mallett (support@autohotkey.com)
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15. */
  16.  
  17. #ifndef window_h
  18. #define window_h
  19.  
  20. #include "defines.h"
  21. #include "globaldata.h"
  22. #include "util.h" // for strlcpy()
  23.  
  24.  
  25. // Note: it is apparently possible for a hidden window to be the foreground
  26. // window (it just looks strange).  If DetectHiddenWindows is off, set
  27. // target_window to NULL if it's hidden.  Doing this prevents, for example,
  28. // WinClose() from closing the hidden foreground if it's some important hidden
  29. // window like the shell or the desktop:
  30. #define USE_FOREGROUND_WINDOW(title, text, exclude_title, exclude_text)\
  31.     ((*title == 'A' || *title == 'a') && !*(title + 1) && !*text && !*exclude_title && !*exclude_text)
  32. #define SET_TARGET_TO_ALLOWABLE_FOREGROUND(detect_hidden_windows) \
  33. {\
  34.     if (target_window = GetForegroundWindow())\
  35.         if (!(detect_hidden_windows) && !IsWindowVisible(target_window))\
  36.             target_window = NULL;\
  37. }
  38. #define IF_USE_FOREGROUND_WINDOW(detect_hidden_windows, title, text, exclude_title, exclude_text)\
  39. if (USE_FOREGROUND_WINDOW(title, text, exclude_title, exclude_text))\
  40. {\
  41.     SET_TARGET_TO_ALLOWABLE_FOREGROUND(detect_hidden_windows)\
  42. }
  43.  
  44.  
  45.  
  46. inline bool IsTextMatch(char *aHaystack, char *aNeedle)
  47. // Generic helper function used by WindowSearch and other things.
  48. // To help performance, it's the caller's responsibility to ensure that all params are not NULL.
  49. {
  50.     if (!*aNeedle) // The empty string is always found, regardless of mode.
  51.         return true;
  52.     switch(g.TitleMatchMode)
  53.     {
  54.     case FIND_ANYWHERE:        return strstr(aHaystack, aNeedle);
  55.     case FIND_REGEX:           return RegExMatch(aHaystack, aNeedle);
  56.     case FIND_IN_LEADING_PART: return !strncmp(aHaystack, aNeedle, strlen(aNeedle));
  57.     default: // Otherwise: Exact match.
  58.         return !strcmp(aHaystack, aNeedle); 
  59.     }
  60. }
  61.  
  62.  
  63.  
  64. #define SEARCH_PHRASE_SIZE 1024
  65. // Info from AutoIt3 source: GetWindowText fails under 95 if >65535, WM_GETTEXT randomly fails if > 32767.
  66. // My: And since 32767 is what AutoIt3 passes to the API functions as the size (not the length, i.e.
  67. // it can only store 32766 if room is left for the zero terminator) we'll use that for the size too.
  68. // Note: MSDN says (for functions like GetWindowText): "Specifies the maximum number of characters to
  69. // copy to the buffer, including the NULL character. If the text exceeds this limit, it is truncated."
  70. #define WINDOW_TEXT_SIZE 32767
  71. #define WINDOW_CLASS_SIZE 1024  // Haven't found anything that documents how long one can be, so use this.
  72.  
  73. // Bitwise fields to support multiple criteria in v1.0.36.02
  74. #define CRITERION_TITLE 0x01
  75. #define CRITERION_ID    0x02
  76. #define CRITERION_PID   0x04
  77. #define CRITERION_CLASS 0x08
  78. #define CRITERION_GROUP 0x10
  79.  
  80. class WindowSearch
  81. {
  82.     // One of the reasons for having this class is to avoid fetching PID, Class, and Window Text
  83.     // when only the criteria have changed but not the candidate window.  This happens when called
  84.     // from the WinGroup class.  Another reason is that it's probably more understandable than
  85.     // the old way, while eliminating some redundant code as well.
  86.  
  87. public:
  88.     DWORD mCriteria; // Which criteria are currently in effect (ID, PID, Class, Title, etc.)
  89.  
  90.     // Controlled and initialized by SetCriteria():
  91.     global_struct *mSettings;                 // Settings such as TitleMatchMode and DetectHiddenWindows.
  92.     char mCriterionTitle[SEARCH_PHRASE_SIZE]; // For storing the title.
  93.     char mCriterionClass[SEARCH_PHRASE_SIZE]; // For storing the "ahk_class" class name.
  94.     size_t mCriterionTitleLength;             // Length of mCriterionTitle.
  95.     char *mCriterionExcludeTitle;             // ExcludeTitle.
  96.     size_t mCriterionExcludeTitleLength;      // Length of the above.
  97.     char *mCriterionText;                     // WinText.
  98.     char *mCriterionExcludeText;              // ExcludeText.
  99.     HWND mCriterionHwnd;                      // For "ahk_id".
  100.     DWORD mCriterionPID;                      // For "ahk_pid".
  101.     WinGroup *mCriterionGroup;                // For "ahk_group".
  102.  
  103.     bool mFindLastMatch; // Whether to keep searching even after a match is found, so that last one is found.
  104.     int mFoundCount;     // Accumulates how many matches have been found (either 0 or 1 unless mFindLastMatch==true).
  105.     HWND mFoundParent;   // Must be separate from mCandidateParent because some callers don't have access to IsMatch()'s return value.
  106.     HWND mFoundChild;    // Needed by EnumChildFind() to store its result, and other things.
  107.  
  108.     HWND *mAlreadyVisited;      // Array of HWNDs to exclude from consideration.
  109.     int mAlreadyVisitedCount;   // Count of items in the above.
  110.     WindowSpec *mFirstWinSpec;  // Linked list used by the WinGroup commands.
  111.     ActionTypeType mActionType; // Used only by WinGroup::PerformShowWindow().
  112.     int mTimeToWaitForClose;    // Same.
  113.     Var *mArrayStart;           // Used by WinGetList() to fetch an array of matching HWNDs.
  114.  
  115.     // Controlled by the SetCandidate() method:
  116.     HWND mCandidateParent;
  117.     DWORD mCandidatePID;
  118.     char mCandidateTitle[WINDOW_TEXT_SIZE];  // For storing title or class name of the given mCandidateParent.
  119.     char mCandidateClass[WINDOW_CLASS_SIZE]; // Must not share mem with mCandidateTitle because even if ahk_class is in effect, ExcludeTitle can also be in effect.
  120.  
  121.     void SetCandidate(HWND aWnd) // Must be kept thread-safe since it may be called indirectly by the hook thread.
  122.     {
  123.         // For performance reasons, update the attributes only if the candidate window changed:
  124.         if (mCandidateParent != aWnd)
  125.         {
  126.             mCandidateParent = aWnd;
  127.             UpdateCandidateAttributes(); // In case mCandidateParent isn't NULL, update the PID/Class/etc. based on what was set above.
  128.         }
  129.     }
  130.  
  131.     ResultType SetCriteria(global_struct &aSettings, char *aTitle, char *aText, char *aExcludeTitle, char *aExcludeText);
  132.     void UpdateCandidateAttributes();
  133.     HWND IsMatch(bool aInvert = false);
  134.  
  135.     WindowSearch() // Constructor.
  136.         // For performance and code size, only the most essential members are initialized.
  137.         // The others do not require it or are intialized by SetCriteria() or SetCandidate().
  138.         : mCriteria(0), mCriterionExcludeTitle("") // ExcludeTitle is referenced often, so should be initialized.
  139.         , mFoundCount(0), mFoundParent(NULL) // Must be initialized here since none of the member functions is allowed to do it.
  140.         , mFoundChild(NULL) // ControlExist() relies upon this.
  141.         , mCandidateParent(NULL)
  142.         // The following must be initialized because it's the object user's responsibility to override
  143.         // them in those relatively rare cases when they need to be.  WinGroup::ActUponAll() and
  144.         // WinGroup::Deactivate() (and probably other callers) rely on these attributes being retained
  145.         // after they were overridden even upon multiple subsequent calls to SetCriteria():
  146.         , mFindLastMatch(false), mAlreadyVisited(NULL), mAlreadyVisitedCount(0), mFirstWinSpec(NULL), mArrayStart(NULL)
  147.     {
  148.     }
  149. };
  150.  
  151.  
  152.  
  153. struct control_list_type
  154. {
  155.     // For something this simple, a macro is probably a lot less overhead that making this struct
  156.     // non-POD and giving it a constructor:
  157.     #define CL_INIT_CONTROL_LIST(cl) \
  158.         cl.is_first_iteration = true;\
  159.         cl.total_classes = 0;\
  160.         cl.total_length = 0;\
  161.         cl.buf_free_spot = cl.class_buf; // Points to the next available/writable place in the buf.
  162.     bool fetch_hwnds;         // True if fetching HWND of each control rather than its ClassNN.
  163.     bool is_first_iteration;  // Must be initialized to true by Enum's caller.
  164.     int total_classes;        // Must be initialized to 0.
  165.     VarSizeType total_length; // Must be initialized to 0.
  166.     VarSizeType capacity;     // Must be initialized to size of the below buffer.
  167.     char *target_buf;         // Caller sets it to NULL if only the total_length is to be retrieved.
  168.     #define CL_CLASS_BUF_SIZE (32 * 1024) // Even if class names average 50 chars long, this supports 655 of them.
  169.     char class_buf[CL_CLASS_BUF_SIZE];
  170.     char *buf_free_spot;      // Must be initialized to point to the beginning of class_buf.
  171.     #define CL_MAX_CLASSES 500  // The number of distinct class names that can be supported in a single window.
  172.     char *class_name[CL_MAX_CLASSES]; // Array of distinct class names, stored consecutively in class_buf.
  173.     int class_count[CL_MAX_CLASSES];  // The quantity found for each of the above classes.
  174. };
  175.  
  176. struct MonitorInfoPackage // A simple struct to help with EnumDisplayMonitors().
  177. {
  178.     int count;
  179.     #define COUNT_ALL_MONITORS INT_MIN  // A special value that can be assigned to the below.
  180.     int monitor_number_to_find;  // If this is left as zero, it will find the primary monitor by default.
  181.     MONITORINFOEX monitor_info_ex;
  182. };
  183.  
  184. struct pid_and_hwnd_type
  185. {
  186.     DWORD pid;
  187.     HWND hwnd;
  188. };
  189.  
  190. struct length_and_buf_type
  191. {
  192.     size_t total_length;
  193.     size_t capacity;
  194.     char *buf;
  195. };
  196.  
  197. struct class_and_hwnd_type
  198. {
  199.     char *class_name;
  200.     bool is_found;
  201.     int class_count;
  202.     HWND hwnd;
  203. };
  204.  
  205. struct point_and_hwnd_type
  206. {
  207.     POINT pt;
  208.     RECT rect_found;
  209.     HWND hwnd_found;
  210.     double distance;
  211. };
  212.  
  213.  
  214. HWND WinActivate(global_struct &aSettings, char *aTitle, char *aText, char *aExcludeTitle, char *aExcludeText
  215.     , bool aFindLastMatch = false
  216.     , HWND aAlreadyVisited[] = NULL, int aAlreadyVisitedCount = 0);
  217. HWND SetForegroundWindowEx(HWND aTargetWindow);
  218.  
  219. // Defaulting to a non-zero wait-time solves a lot of script problems that would otherwise
  220. // require the user to specify the last param (or use WinWaitClose):
  221. #define DEFAULT_WINCLOSE_WAIT 20
  222. HWND WinClose(global_struct &aSettings, char *aTitle, char *aText, int aTimeToWaitForClose = DEFAULT_WINCLOSE_WAIT
  223.     , char *aExcludeTitle = "", char *aExcludeText = "", bool aKillIfHung = false);
  224. HWND WinClose(HWND aWnd, int aTimeToWaitForClose = DEFAULT_WINCLOSE_WAIT, bool aKillIfHung = false);
  225.  
  226. HWND WinActive(global_struct &aSettings, char *aTitle, char *aText, char *aExcludeTitle, char *aExcludeText
  227.     , bool aUpdateLastUsed = false);
  228.  
  229. HWND WinExist(global_struct &aSettings, char *aTitle, char *aText, char *aExcludeTitle, char *aExcludeText
  230.     , bool aFindLastMatch = false, bool aUpdateLastUsed = false
  231.     , HWND aAlreadyVisited[] = NULL, int aAlreadyVisitedCount = 0);
  232.  
  233. HWND GetValidLastUsedWindow(global_struct &aSettings);
  234.  
  235. BOOL CALLBACK EnumParentFind(HWND hwnd, LPARAM lParam);
  236. BOOL CALLBACK EnumChildFind(HWND hwnd, LPARAM lParam);
  237.  
  238.  
  239. // Use a fairly long default for aCheckInterval since the contents of this function's loops
  240. // might be somewhat high in overhead (especially SendMessageTimeout):
  241. #define SB_DEFAULT_CHECK_INTERVAL 50
  242. ResultType StatusBarUtil(Var *aOutputVar, HWND aBarHwnd, int aPartNumber = 1, char *aTextToWaitFor = ""
  243.     , int aWaitTime = -1, int aCheckInterval = SB_DEFAULT_CHECK_INTERVAL);
  244. HWND ControlExist(HWND aParentWindow, char *aClassNameAndNum = NULL);
  245. BOOL CALLBACK EnumControlFind(HWND aWnd, LPARAM lParam);
  246.  
  247. #define MSGBOX_NORMAL (MB_OK | MB_SETFOREGROUND)
  248. #define MSGBOX_TEXT_SIZE (1024 * 8)
  249. #define DIALOG_TITLE_SIZE 1024
  250. int MsgBox(int aValue);
  251. int MsgBox(char *aText = "", UINT uType = MSGBOX_NORMAL, char *aTitle = NULL, double aTimeout = 0, HWND aOwner = NULL);
  252. HWND FindOurTopDialog();
  253. BOOL CALLBACK EnumDialog(HWND hwnd, LPARAM lParam);
  254.  
  255. HWND WindowOwnsOthers(HWND aWnd);
  256. BOOL CALLBACK EnumParentFindOwned(HWND aWnd, LPARAM lParam);
  257. HWND GetNonChildParent(HWND aWnd);
  258. HWND GetTopChild(HWND aParent);
  259. bool IsWindowHung(HWND aWnd);
  260.  
  261. // Defaults to a low timeout because a window may have hundreds of controls, and if the window
  262. // is hung, each control might result in a delay of size aTimeout during an EnumWindows.
  263. // It shouldn't need much time anyway since the moment the call to SendMessageTimeout()
  264. // is made, our thread is suspended and the target thread's WindowProc called directly.
  265. // In addition:
  266. // Whenever using SendMessageTimeout(), our app will be unresponsive until
  267. // the call returns, since our message loop isn't running.  In addition,
  268. // if the keyboard or mouse hook is installed, the events will lag during
  269. // this call.  So keep the timeout value fairly short.  UPDATE: Need a longer
  270. // timeout because otherwise searching will be inconsistent / unreliable for the
  271. // slow Title Match method, since some apps are lazy about keeping their
  272. // message pumps running, such as during long disk I/O operations, and thus
  273. // may sometimes (randomly) take a long time to respond to the WM_GETTEXT message.
  274. // 5000 seems about the largest value that should ever be needed since this is what
  275. // Windows uses as the cutoff for determining if a window has become "unresponsive":
  276. int GetWindowTextTimeout(HWND aWnd, char *aBuf = NULL, int aBufSize = 0, UINT aTimeout = 5000);
  277. void SetForegroundLockTimeout();
  278.  
  279.  
  280. // Notes about the below macro:
  281. // Update for v1.0.40.01:
  282. // In earlier versions, a critical thread that displayed a dialog would discard any pending events
  283. // that were waiting to start new threads (since in most cases, the dialog message pump would
  284. // route those events directly to a window proc, which would then repost them with a NULL hwnd
  285. // to prevent bouncing, which in turn would cause the dialog pump to discard them).  To avoid
  286. // this and make the behavior more useful and intuitive, this has been changed so that any
  287. // pending threads will launch right before the dialog is displayed.  But later, when the user
  288. // dismisses the dialog, the thread becomes critical again.
  289. // 
  290. // Update for v1.0.38.04: Rather than setting AllowThreadToBeInterrupted unconditionally to
  291. // true, make it reflect the state of g.ThreadIsCritical.  This increases flexbility by allowing
  292. // threads to stay interrruptible even when they're displaying a dialog.  In such cases, an
  293. // incoming thread-event such as a hotkey will get routed to our MainWindowProc by the dialog's
  294. // message pump; and from there it will get reposted to our queue, and then get pumped again.
  295. // This bouncing effect may impact performance slightly but seems warranted to maintain
  296. // flexibility of the "Critical" command as well as its ability to buffer incoming events.
  297. //
  298. // If our thread's message queue has any message pending whose HWND member is NULL -- or even
  299. // normal messages which would be routed back to the thread by the WindowProc() -- clean them
  300. // out of the message queue before launching the dialog's message pump below.  That message pump
  301. // doesn't know how to properly handle such messages (it would either lose them or dispatch them
  302. // at times we don't want them dispatched).  But first ensure the current quasi-thread is
  303. // interruptible, since it's about to display a dialog so there little benefit (and a high cost)
  304. // to leaving it uninterruptible.  The "high cost" is that MsgSleep (our main message pump) would
  305. // filter out (leave queued) certain messages if the script were uninterruptible.  Then when it
  306. // returned, the dialog message pump below would start, and it would discard or misroute the
  307. // messages.
  308. // If this is not done, the following scenario would also be a problem:
  309. // A newly launched thread (in its period of uninterruptibility) displays a dialog.  As a consequence,
  310. // the dialog's message pump starts dispatching all messages.  If during this brief time (before the
  311. // thread becomes interruptible) a hotkey/hotstring/custom menu item/gui thread is dispatched to one
  312. // of our WindowProc's, and then posted to our thread via PostMessage(NULL,...), the item would be lost
  313. // because the dialog message pump discards messages that lack an HWND (since it doesn't know how to
  314. // dispatch them to a Window Proc).
  315. // GetQueueStatus() is used because unlike PeekMessage() or GetMessage(), it might not yield
  316. // our timeslice if the CPU is under heavy load, which would be good to improve performance here.
  317. #define DIALOG_PREP bool thread_was_critical = DialogPrep();
  318. // v1.0.40.01: Turning off critical during the dialog is relied upon by ResumeUnderlyingThread(),
  319. // UninterruptibleTimeout(), and KILL_AUTOEXEC_TIMER.  Doing it this way also seems more maintainable
  320. // than some other approach such as storing a new flag in the "g" struct that says whether it is currently
  321. // displaying a dialog and waiting for it to finish.
  322. #define DIALOG_END \
  323. {\
  324.     g.ThreadIsCritical = thread_was_critical;\
  325.     g.AllowThreadToBeInterrupted = !thread_was_critical;\
  326. }
  327. bool DialogPrep();
  328.  
  329. #endif
  330.